package org.jeecg.modules.utils.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.dto.message.MsgDingdingGroupDTO;
import org.jeecg.common.constant.enums.MessageTypeEnum;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.Md5Util;
import org.jeecg.modules.message.entity.SysMessageTemplate;
import org.jeecg.modules.message.service.ISysMessageTemplateService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.entity.SysUserRole;
import org.jeecg.modules.system.service.ISysUserRoleService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.util.dingding.TextEntity;
import org.jeecg.modules.utils.dto.SmsDto;
import org.jeecg.modules.utils.service.IAlertService;
import org.jeecg.modules.wms.sys.entity.*;
import org.jeecg.modules.wms.sys.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AlertServiceImpl implements IAlertService {

    @Autowired
    private ISysMessageTemplateService sysMessageTemplateService;

    @Autowired
    private ISysSmsTemplateLabelService sysSmsTemplateLabelService;

    @Autowired
    private ISysSmsTriggerService sysSmsTriggerService;

    @Autowired
    private ISysSmsTriggerLabelService sysSmsTriggerLabelService;

    @Autowired
    private ISysSendTargetService sysSendTargetService;

    @Autowired
    private ISysSendTargetLabelService sysSendTargetLabelService;

    @Autowired
    private ISysSendTargetUserService sysSendTargetUserService;

    @Autowired
    private ISysSendTargetRoleService sysSendTargetRoleService;

    @Autowired
    private ISysUserRoleService sysUserRoleService;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysSendDingService sysSendDingService;

    @Override
    public void send(SmsDto dto) throws Exception {
        // 第一步,根据templatecode获取发送模版
        List<SysMessageTemplate> sysMessageTemplates = sysMessageTemplateService.selectByCode(dto.getTemplateCode());

        if (sysMessageTemplates.size() <= 0) {
            throw new Exception("未找到模版");
        }
        SysMessageTemplate sysMessageTemplate = sysMessageTemplates.get(0);
        // 第二步,获取labels;
        List<SysSmsTemplateLabel> sysSmsTemplateLabels = sysSmsTemplateLabelService.lambdaQuery().eq(SysSmsTemplateLabel::getSysSmsTemplateId, sysMessageTemplate.getId()).list();

        if (sysSmsTemplateLabels.size() <= 0) {
            throw new Exception("模版没有匹配的标签");
        }
        SortedMap<String, String> sortedMap = new TreeMap();

        // 第三步,替换labels
        sysSmsTemplateLabels.stream().forEach(sysSmsTemplateLabel -> {
            dto.getData().forEach((k, v) -> {
                if (v != null) {
                    sysSmsTemplateLabel.setValue(sysSmsTemplateLabel.getValue().replace("${" + k + "}", v.toString()));
                }
            });

            // 第四步,把labels排序
            sortedMap.put(sysSmsTemplateLabel.getName(), sysSmsTemplateLabel.getValue());
        });

        sortedMap.put("sysMessageTemplate", sysMessageTemplate.getId());

        // 生成labels hash
        String md5Encode = Md5Util.md5Encode(JSON.toJSONString(sortedMap), "utf-8");

        // 根据hash查找对应的trigger
        SysSmsTrigger smsTrigger = sysSmsTriggerService.lambdaQuery().eq(SysSmsTrigger::getCode, md5Encode)
                .eq(SysSmsTrigger::getSysSmsTemplateId, sysMessageTemplate.getId()).one();

        // 如果有,判断是否在已触发状态
        if (!dto.getOnce()) {
            if (smsTrigger != null) {
                if (smsTrigger.getStatus().equals("firing")) {
                    // 如果是已触发状态,就啥也不干了
                    return;
                } else {
                    // 如果是其它状态,更新
                    smsTrigger.setStatus("firing");
                    sysSmsTriggerService.updateById(smsTrigger);
                }
            } else {
                // 如果没有,插入一条新的
                smsTrigger = new SysSmsTrigger();
                smsTrigger.setCode(md5Encode);
                smsTrigger.setStatus("firing");
                smsTrigger.setSysSmsTemplateId(sysMessageTemplate.getId());
                sysSmsTriggerService.save(smsTrigger);

                // 更新完trigger还要更新trigger的label
                SysSmsTrigger finalSmsTrigger = smsTrigger;
                List<SysSmsTriggerLabel> smsTriggerLabels = sysSmsTemplateLabels.stream().map(l -> {
                    SysSmsTriggerLabel sysSmsTriggerLabel = new SysSmsTriggerLabel();
                    sysSmsTriggerLabel.setName(l.getName());
                    sysSmsTriggerLabel.setValue(l.getValue());
                    sysSmsTriggerLabel.setSysSmsTriggerId(finalSmsTrigger.getId());
                    return sysSmsTriggerLabel;
                }).collect(Collectors.toList());
                sysSmsTriggerLabelService.saveBatch(smsTriggerLabels);
            }
        }

        //  6. 根据label查找发送对象
        // 获取所有的sendtarget
        List<SysSendTarget> sysSendTargets = sysSendTargetService.list();
        List<String> sysSendTargetIds = sysSendTargets.stream().map(t -> t.getId()).collect(Collectors.toList());

        // 获取所有的labels
        List<SysSendTargetLabel> allSysSendTargetLabels = sysSendTargetLabelService.lambdaQuery().in(SysSendTargetLabel::getSysSendTargetId, sysSendTargetIds).list();
        Map<String, List<SysSendTargetLabel>> collect = allSysSendTargetLabels.stream().collect(Collectors.groupingBy(l -> l.getSysSendTargetId()));

        List<String> sendTargetIds = new ArrayList<>();
        for (SysSendTarget sysSendTarget : sysSendTargets) {
            boolean send = true;
            // 如果有一个label不符合,就不发送
            // 目前第一版,只做了完全匹配, name和value一致
            List<SysSendTargetLabel> sendTargetLabels = collect.get(sysSendTarget.getId());
            if (CollectionUtil.isNotEmpty(sendTargetLabels)) {
                for (SysSendTargetLabel l : sendTargetLabels) {
                    if (!sortedMap.containsKey(l.getName())) {
                        send = false;
                        break;
                    }
                    String value = sortedMap.get(l.getName()).toString();
                    if (!value.equals(l.getValue())) {
                        send = false;
                        break;
                    }
                }
                if (!send) {
                    continue;
                }
                sendTargetIds.add(sysSendTarget.getId());
            }
        }

        // 7. 获取发送对象
        if (sendTargetIds.size() > 0) {
            for (String targetId : sendTargetIds) {
                List<SysSendTargetRole> roles = sysSendTargetRoleService.lambdaQuery().eq(SysSendTargetRole::getSysSendTargetId, targetId).list();
                List<String> roleIds = roles.stream().map(r -> r.getRoleId()).collect(Collectors.toList());
                List<SysSendTargetUser> users = sysSendTargetUserService.lambdaQuery().eq(SysSendTargetUser::getSysSendTargetId, targetId).list();
                // 根据roles获取users
                List<SysUserRole> userRoles = roleIds.size() > 0 ? sysUserRoleService.lambdaQuery().in(SysUserRole::getRoleId, roleIds).list() : new ArrayList<>();

                List<String> targetUserIds = new ArrayList<>();

                targetUserIds.addAll(userRoles.stream().map(r -> r.getUserId()).collect(Collectors.toList()));
                targetUserIds.addAll(users.stream().map(u -> u.getUserId()).collect(Collectors.toList()));

                List<SysUser> sysUsers = userService.listByIds(targetUserIds);
                List<String> userNames = sysUsers.stream().map(u -> u.getUsername()).collect(Collectors.toList());

                SysSendTarget sendTarget = sysSendTargetService.getById(targetId);
                if (StringUtils.isNotBlank(sendTarget.getCode())) {
                    MessageDTO messageDTO = new MessageDTO();
                    messageDTO.setToUser(String.join(",", userNames));
                    messageDTO.setData(dto.getData());
                    messageDTO.setTemplateCode(dto.getTemplateCode());
                    messageDTO.setTitle(sysMessageTemplate.getTemplateName());

                    String[] methods = sendTarget.getMethod().split(",");
                    if (methods.length > 0) {
                        Arrays.stream(methods).forEach(t -> {
                            messageDTO.setType(t);
                            if (MessageTypeEnum.XT.getType().equals(t)) {
                                sysBaseAPI.sendTemplateMessage(messageDTO);
                            } else if (MessageTypeEnum.DD.getType().equals(t)) {

                                SysSendDing sysSendDing = sysSendDingService.lambdaQuery().eq(SysSendDing::getSysSendTargetId, sendTarget.getId()).one();
                                if (ObjectUtil.isNotEmpty(sysSendDing)) {
                                    // 查询钉钉告警配置
                                    MsgDingdingGroupDTO message = new MsgDingdingGroupDTO();
                                    if (StringUtils.isNotBlank(sysSendDing.getUrl())) {
                                        message.setSecret(sysSendDing.getSecretKey());
                                        message.setWebhook(sysSendDing.getUrl());
                                        message.setData(dto.getData());
                                        message.setTemplateCode(dto.getTemplateCode());
                                        sysBaseAPI.sendMsgDingdingGroup(message);
                                    } else {
                                        log.error("告警信息未发送成功，原因：配置钉钉告警信息,未配置机器人地址");
                                    }
                                } else {
                                    log.error("告警信息未发送成功，原因：当前发送配置未配置钉钉告警信息");
                                }
                            }
                        });
                    }
                }
            }
        }

    }

    @Override
    public void inActive(SmsDto dto) throws Exception {
        List<SysMessageTemplate> sysMessageTemplates = sysMessageTemplateService.selectByCode(dto.getTemplateCode());

        if (sysMessageTemplates.size() <= 0) {
            throw new Exception("未找到模版");
        }
        SysMessageTemplate sysMessageTemplate = sysMessageTemplates.get(0);
        // 第二步,获取labels;
        List<SysSmsTemplateLabel> sysSmsTemplateLabels = sysSmsTemplateLabelService.lambdaQuery().eq(SysSmsTemplateLabel::getSysSmsTemplateId, sysMessageTemplate.getId()).list();

        if (sysSmsTemplateLabels.size() <= 0) {
            throw new Exception("模版没有匹配的标签");
        }
        SortedMap<String, String> sortedMap = new TreeMap();

        // 第三步,替换labels
        sysSmsTemplateLabels.stream().forEach(sysSmsTemplateLabel -> {
            dto.getData().forEach((k, v) -> {
                sysSmsTemplateLabel.setValue(sysSmsTemplateLabel.getValue().replace("${" + k + "}", v.toString()));
            });

            // 第四步,把labels排序
            sortedMap.put(sysSmsTemplateLabel.getName(), sysSmsTemplateLabel.getValue());
        });

        sortedMap.put("sysMessageTemplate", sysMessageTemplate.getId());

        // 生成labels hash
        String md5Encode = Md5Util.md5Encode(JSON.toJSONString(sortedMap), "utf-8");

        // 根据hash查找对应的trigger
        SysSmsTrigger smsTrigger = sysSmsTriggerService.lambdaQuery().eq(SysSmsTrigger::getCode, md5Encode).one();

        if (smsTrigger != null) {
            if (smsTrigger.getStatus().equals("firing")) {
                smsTrigger.setStatus("inactive");
                sysSmsTriggerService.updateById(smsTrigger);
                return;
            }
        }
    }
}
